package wn.tcpip.socket.util;

import wn.tcpip.socket.util.data.DateStyle;
import wn.tcpip.socket.util.data.DateUtil;
import wn.tcpip.socket.netty.model.GpsEquipmentPositionEntity;
import org.apache.commons.lang3.StringUtils;

import java.util.Calendar;
import java.util.Date;

/**
 * 协议处理中的一些工具类
 * 
 * @author zhu@goome 2010/03/27
 *
 */
public class ProtocolUtil {

	//private static final Logger logger = LoggerFactory.getLogger(ProtocolUtil.class);

	/**
	 * 把16进制的时间转换成常规日期时间
	 * 
	 * @param hexDateTime 终端上来的16进制时间
	 * @return
	 */
	public static  String getSimpleFormatDateTime(String hexDateTime) {
		int[] iDateTiem = new int[6];

		for (int j = 1; j <= 6; j++) {
			iDateTiem[j - 1] = Integer.parseInt(hexDateTime.substring(
					(j - 1) * 2, j * 2), 16);
		}

		String head = "20";
		if ((iDateTiem[0] + "").length() == 1) {
			head = "200";
		}
		return head + iDateTiem[0] + "-" + iDateTiem[1] + "-" + iDateTiem[2]
				+ " " + iDateTiem[3] + ":" + iDateTiem[4] + ":" + iDateTiem[5];
	}

	/*
	 * 根据当前时间构建16进制时间串
	 */
	public static String buildHexDateTime(){
		Calendar cal = Calendar.getInstance();
		Integer year = cal.get(Calendar.YEAR);
		int month = cal.get(Calendar.MONTH)+1;
		int day = cal.get(Calendar.DAY_OF_MONTH);
		int hour = cal.get(Calendar.HOUR);
		int minute = cal.get(Calendar.MINUTE);
		int seconds = cal.get(Calendar.SECOND);
		StringBuilder dateBuild = new StringBuilder(ProtocolUtil.getHexIntString(Integer.parseInt(year.toString().substring(2)), 2));
		dateBuild.append(ProtocolUtil.getHexIntString(month, 2));
		dateBuild.append(ProtocolUtil.getHexIntString(day, 2));
		dateBuild.append(ProtocolUtil.getHexIntString(hour, 2));
		dateBuild.append(ProtocolUtil.getHexIntString(minute, 2));
		dateBuild.append(ProtocolUtil.getHexIntString(seconds, 2));
		return dateBuild.toString();
	}

	/**
	 * 将16进制字符串转成2进制字符串
	 * 
	 * @param addInfo 数据(16进制)
	 * @param length 目标byte的位数
	 * @return
	 */
	public static String str2ByteString(String addInfo,int length){
		// 获得状态位
		int status = Integer.parseInt(addInfo, 16);
		// 转换成字节位
		String str2 = Integer.toBinaryString(status);
		// 将2个字节补满，左补0
		str2 = StringUtils.leftPad(str2, length, '0');
		return str2;
	}

	/**
	 * 根据int获取相应的16进制的字符串<br>
	 *  9-> 09,15->0F,补充到指定的长度
	 * 
	 * @param i 10进制整型数
	 * @param length  目标16进制数据的长度(1字节是2位)
	 * @return
	 */
	public static String getHexIntString(int i,int length) {
		String str = Integer.toHexString(i);
		if(str.length() < length){
			str = StringUtils.leftPad(str, length, '0');
		}
		return str.toUpperCase();
	}

	/**
	 * 构造服务器返回数据
	 * 
	 * @param protocolID 协议号
	 * @param sequenceNum 信息序号
	 * @return 返回给终端的响应
	 */
	public static String buildResponseString(String protocolID,int sequenceNum){		

		// 内容长度
		String contentLength = "05";		
		// 序列号(2字节)
		// 转成16进制
		//		log.info("终端上来的序列号:" + sequenceNum);
		String xuliehao = Integer.toHexString(sequenceNum);
		//		log.info("返回终端的序列号:" + xuliehao);
		// 补足成4位，2字节
		xuliehao = StringUtils.leftPad(xuliehao, 4, '0');

		// 需要crc校验的位
		String crcString = contentLength + protocolID + xuliehao;
		String crcCode = getCrc16Code(crcString);

		// 组装返回给终端的数据包
		StringBuilder response = new StringBuilder();
		// 包头(2字节)
		response.append("7878");
		// 内容长度(1字节)
		response.append(contentLength);
		// 协议号(1字节)
		response.append(protocolID);
		// 序列号(2字节)
		response.append(xuliehao);
		// CRC校验码（2字节）
		response.append(crcCode);
		response.append("0D0A");
		return response.toString();
	}

	/**
	 * 构造服务器返回数据
	 * 
	 * @param protocolID
	 *            协议号
	 * @param sequenceNum
	 *            信息序号
	 * @param content 信息内容(已经转换成16进制的了)
	 * @return 返回给终端的响应
	 */
	public static String buildResponseString(String protocolID,
			int sequenceNum, String content) {

		int length = 5 + content.length() /2 ;

		// 内容长度(1字节)
		String contentLength = getHexIntString(length, 2);
		// 序列号(2字节)
		// 转成16进制
		// log.info("终端上来的序列号:" + sequenceNum);
		String xuliehao = Integer.toHexString(sequenceNum);
		// log.info("返回终端的序列号:" + xuliehao);
		// 补足成4位，2字节

		xuliehao = StringUtils.leftPad(xuliehao, 4, '0');

		// 需要crc校验的位
		String crcString = contentLength + protocolID + content +xuliehao;
		String crcCode = getCrc16Code(crcString);

		// 组装返回给终端的数据包
		StringBuilder response = new StringBuilder();
		// 包头(2字节)
		response.append("7878");
		// 内容长度(1字节)
		response.append(contentLength);
		// 协议号(1字节)
		response.append(protocolID);
		response.append(content);
		// 序列号(2字节)
		response.append(xuliehao);
		// CRC校验码（2字节）
		response.append(crcCode);
		response.append("0D0A");
		return response.toString();
	}

	/**
	 * 16进制字符串获取crc16校验码
	 * 
	 * @param crcString 终端传过来的16进制的字符串
	 * @return CRC16的校验码
	 */
	public static String getCrc16Code(String crcString){
		// 转换成字节数组
		byte[] creBytes = Byte2Hex.HexString2Bytes(crcString);

		// 开始crc16校验码计算
		CRC16Util crc16 = new CRC16Util();
		crc16.reset();
		crc16.update(creBytes);
		int crc = crc16.getCrcValue();
		// 16进制的CRC码
		String crcCode = Integer.toHexString(crc);
		// 补足到4位
		if (crcCode.length() < 4) {
			crcCode = StringUtils.leftPad(crcCode, 4, '0');
		}
		return crcCode;
	}

	/**
	 * 将字符串转换成byte数组
	 * 
	 * @param addInfo 数据(16进制)
	 * @param length 目标byte的位数
	 * @return 
	 */
	public static byte[] decodeStringToBytes(String addInfo,int length) {
		// 获得状态位
		int status = Integer.parseInt(addInfo, 16);
		// 转换成字节位
		String str2 = Integer.toBinaryString(status);
		// 将字节补满，左补0

		str2 = StringUtils.leftPad(str2, length, '0');
		byte[] returnValue = new byte[length];
		for (int i = 0; i < length; i++) {
			returnValue[i] = Byte.parseByte(str2.substring(i, i + 1));
		}
		return returnValue;
	}

	/**
	 * 构造发送给终端的指令数据包<br>
	 * 
	 * @param content
	 *            指令内容(转换后的16进制字节字符串)
	 * @param serialNo
	 *            指令流水号(4字节 16进制字符串)
	 * @return
	 */
	public static String buildSendCmdPackage(String content, String serialNo) {

		// 指令流水号 即服务器标志位
		// 包长度 协议号(1字节)+指令长度(1字节) + 指令流水号(4字节)+
		// 内容长度(N)+包序号(2字节)+crc校验(2字节)
		int length = 1 + 1 + 4 + content.length() / 2 + 4;
		StringBuilder sb = new StringBuilder();
		// 包长度
		sb.append(ProtocolUtil.getHexIntString(length, 2));
		// 协议号:80
		sb.append("80");
		// 指令内容长度(指令流水号(4字节)+内容长度(N))
		int contentLen = 4 + content.length() / 2;
		// 指令内容长度：1字节
		sb.append(ProtocolUtil.getHexIntString(contentLen, 2));
		// 指令流水号(4字节)
		sb.append(serialNo);
		// 信息内容
		sb.append(content);
		// 信息序列号(随便写一个)
		sb.append("00A0");
		// CRC校验码
		String crc = ProtocolUtil.getCrc16Code(sb.toString());
		sb.append(crc);
		sb.append("0D0A");
		return "7878" + sb.toString();
	}

	public static GpsEquipmentPositionEntity parseEntity(String content) {
		GpsEquipmentPositionEntity entity = new GpsEquipmentPositionEntity();
		entity.setImei(content.substring(1));
		String dateTimeOrgi = content.substring(0, 6 * 2);
		String dateTime = ProtocolUtil.getSimpleFormatDateTime(dateTimeOrgi);
		entity.setSj(dateTime);
		entity.setSjny(DateUtil.StringToString(entity.getSj(), DateStyle.YYYYMM));
		content = content.substring(6 * 2);
		// ====GPS 信息====
		// gps 信息长度，参与定位的卫星数(1 字节),gps 描述信息
		// 这个 1 字节前 4 位说明 gps 信息长度，后 4 位说明参与定位的卫星数
		String gpsDescriptInfo = content.substring(0, 1 * 2);
		content = content.substring(1 * 2);// gps 信息长度
		int gpsLength = Integer.parseInt(gpsDescriptInfo.substring(0, 1), 16);
		// 参与定位的卫星数
		int satelliteNum = Integer.parseInt(gpsDescriptInfo.substring(1, 2), 16);
		entity.setScoutsatellite(satelliteNum);
		// 获取 gps 信息
		String gpsInfo = content.substring(0, (gpsLength - 1) * 2);
		content = content.substring((gpsLength - 1) * 2);
		// 维度：4 字节
		String weiDuOrgi = gpsInfo.substring(0, 4 * 2);
		// 处理纬度
		String weidu = new Double(Integer.parseInt(weiDuOrgi, 16)) / 1800000 + "";
		gpsInfo = gpsInfo.substring(4 * 2);
		// 经度：4 字节
		String jingDuOrgi = gpsInfo.substring(0, 4 * 2);
		// 处理经度
		String jingdu = new Double(Integer.parseInt(jingDuOrgi, 16)) / 1800000 + "";
		gpsInfo = gpsInfo.substring(4 * 2);
		// 速度：1 字节
		String suDu = gpsInfo.substring(0, 1 * 2);
		Integer iSuDu = Integer.parseInt(suDu, 16);
		entity.setSpeed(iSuDu.toString());

		gpsInfo = gpsInfo.substring(1 * 2);
		// 状态，航向:2 字节
		String addInfo = gpsInfo.substring(0, 2 * 2);
		byte[] statusInfo = ProtocolUtil.decodeStringToBytes(addInfo, 16);
		//定位状态
		byte locationStatus = statusInfo[3];
		entity.setState(String.valueOf(locationStatus));
		// 东西经度
		byte jing = statusInfo[4];
		// 如果为西经，西经为负数
		if (jing == 1) {
			jingdu = "-" + jingdu;

		}
		entity.setLongitude(String.valueOf(jingdu));

		// 南北纬度
		byte wei = statusInfo[5];
		// 如果是南纬，南纬为负数
		if (wei == 0) {
			weidu = "-" + weidu;
		}
		entity.setLatitude(weidu);


		// 航向
		String hangxiang = "";
		// 航向占低位的 10 个字节
		for (int i = 6; i < 16; i++) {
			hangxiang = hangxiang + statusInfo[i];
		}
		hangxiang = Integer.parseInt(hangxiang, 2) + "";
		entity.setOrentation(hangxiang);
		//		// gps 扩展位
		//		String gpsExtent = gpsInfo;
		//
		//		// ===== LBS===信息
		//		// MCC:国家码(2 字节)
		//		// MNC:网络运营商码(1 字节)
		//		// LAC:区域码(2 字节)
		//		// CellID:基站码(3 字节)
		//		String lbsInfo = content.substring(0, 8 * 2);
		//		content = content.substring(8 * 2);
		//		// LBS 扩展位
		//		String lbsExtent = content;

		return entity;
	}

}